package top.chengdongqing.mishop.user

import org.springframework.data.repository.findByIdOrNull
import org.springframework.security.crypto.password.PasswordEncoder
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import top.chengdongqing.mishop.common.constants.RegexPatterns
import top.chengdongqing.mishop.common.exception.NotAcceptableException
import top.chengdongqing.mishop.enums.OrderStatus
import top.chengdongqing.mishop.repositories.*
import top.chengdongqing.mishop.user.dto.UserProfileDTO
import top.chengdongqing.mishop.user.vo.UserStatisticsVO
import top.chengdongqing.mishop.utils.VerificationCodeUtils

@Service
class UserService(
    private val userRepository: UserRepository,
    private val orderRepository: OrderRepository,
    private val cartRepository: CartRepository,
    private val favoriteRepository: UserFavoriteRepository,
    private val addressRepository: UserAddressRepository,
    private val verificationCodeUtils: VerificationCodeUtils,
    private val passwordEncoder: PasswordEncoder
) {

    fun statistics(userId: Int): UserStatisticsVO {
        // 查询待支付、待收货、待评价的订单数量
        val ordersMap = orderRepository.countByUserIdAndStatusIn(
            userId,
            listOf(OrderStatus.PENDING_PAYMENT, OrderStatus.PENDING_DELIVERY, OrderStatus.COMPLETED)
        ).associate { it[0] as OrderStatus to (it[1] as Long).toInt() }
        // 查询喜欢的商品数量
        val favoritesCount = favoriteRepository.countByUserId(userId)

        return UserStatisticsVO(
            ordersMap[OrderStatus.PENDING_PAYMENT] ?: 0,
            ordersMap[OrderStatus.PENDING_DELIVERY] ?: 0,
            ordersMap[OrderStatus.COMPLETED] ?: 0,
            favoritesCount
        )
    }

    fun updateProfile(userId: Int, profileDTO: UserProfileDTO) {
        val user = userRepository.findByIdOrNull(userId)!!

        profileDTO.name?.let {
            if (!RegexPatterns.USERNAME.matches(it)) {
                throw NotAcceptableException("昵称格式错误")
            }
            user.name = it
        }
        profileDTO.gender?.let { user.gender = it }
        profileDTO.avatarUrl?.let { user.avatarUrl = it }

        userRepository.save(user)
    }

    fun modifyPhoneNumber(userId: Int, phoneNumber: String, verificationCode: String) {
        // 校验验证码
        verificationCodeUtils.verify(phoneNumber, verificationCode) {
            NotAcceptableException("验证码错误")
        }

        // 判断该手机号是否已被使用
        if (userRepository.existsByPhoneNumber(phoneNumber)) {
            throw NotAcceptableException("该手机号已被使用")
        }

        // 保存新手机号
        val user = userRepository.findById(userId).orElseThrow()
        user.phoneNumber = phoneNumber
        userRepository.save(user)
    }

    fun modifyEmailAddress(userId: Int, emailAddress: String, verificationCode: String) {
        // 校验验证码
        verificationCodeUtils.verify(emailAddress, verificationCode) {
            NotAcceptableException("验证码错误")
        }

        // 判断该邮箱是否已被使用
        if (userRepository.existsByEmailAddress(emailAddress)) {
            throw NotAcceptableException("该邮箱已被使用")
        }

        // 保存新邮箱
        val user = userRepository.findById(userId).orElseThrow()
        user.emailAddress = emailAddress
        userRepository.save(user)
    }

    fun modifyPassword(userId: Int, password: String) {
        // 判断密码格式
        if (!RegexPatterns.PASSWORD.matches(password)) {
            throw NotAcceptableException("密码格式错误")
        }

        // 保存新密码
        val user = userRepository.findById(userId).orElseThrow()
        // 计算密码哈希
        user.password = passwordEncoder.encode(password)
        userRepository.save(user)
    }

    @Transactional
    fun deleteAccount(userId: Int) {
        // 查询是否有进行中的订单
        if (orderRepository.existsByUserIdAndStatusNotIn(userId, listOf(OrderStatus.COMPLETED, OrderStatus.CANCELED))) {
            throw NotAcceptableException("您还有未完成的订单")
        }

        // 尽可能删除用户的个人数据
        userRepository.deleteById(userId)
        cartRepository.deleteAllByUserId(userId)
        addressRepository.deleteAllByUserId(userId)
        favoriteRepository.deleteAllByUserId(userId)
    }
}